﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace LayeredArchitectureSample.DomainModel
{
    internal class TripEnRoute : DomainObject, ITrip
    {
        private readonly ReadOnlyCollection<WareUnitsCounted> _wares;
        private readonly Route _route;

        public TripEnRoute(long id, IEnumerable<WareUnitsCounted> wares, Route route)
            : base(id)
        {
            if (wares == null) throw new ArgumentNullException("wares");
            if (route == null) throw new ArgumentNullException("route");

            if (route.GetType() == typeof(UnspecifiedRoute))
            {
                throw new ArgumentException("Expecting a specified route", "route");
            }

            if (!wares.Any())
            {
                throw new ArgumentException("waresToTake");
            }

            if (route.Waypoints.Count == 0)
            {
                throw new ArgumentException("Expecting a non empty route", "route");
            }

            if (wares.GroupBy(w=>w.Ware).Any(g=>g.Count() > 1))
            {
                throw new ArgumentException("Any ware should be mentioned only once in the list of wares being moved in the trip", "wares");
            }

            _wares = new List<WareUnitsCounted>(wares).AsReadOnly();
            _route = route;
        }

        public Route Route
        {
            get { return _route; }
        }

        public ReadOnlyCollection<WareUnitsCounted> Wares
        {
            get { return _wares; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="route"></param>
        /// <param name="waresToTake"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public void Ship(Route route, IEnumerable<WareUnitsCounted> waresToTake)
        {
            throw new InvalidOperationException("Cannot ship a trip that is en route");
        }

        /// <exception cref="InvalidOperationException"></exception>
        public void MarkAsArrivedToFinalDestination()
        {
            throw new NotImplementedException("This should never be called directly");
        }

        public string Status
        {
            get { return "En route"; }
        }

        public TripState State
        {
            get { return TripState.EnRoute; }
        }
    }
}